/* Copyright(c) 2000, Compaq Computer Corporation
 * Fibre Channel Host Bus Adapter 64-bit, 66MHz PCI 
 * Originally developed and tested on:
 * (front): [chip] Tachyon TS HPFC-5166A/1.2  L2C1090 ...
 *          SP# P225CXCBFIEL6T, Rev XC
 *          SP# 161290-001, Rev XD
 * (back): Board No. 010008-001 A/W Rev X5, FAB REV X5
 *  
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2, or (at your option) any
 * later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 * Written by Don Zimmerman
*/

#ifndef CPQFCTSSTRUCTS_H
#define CPQFCTSSTRUCTS_H

#include <linux/timer.h>	// timer declaration in our host data
#include <linux/tqueue.h>	// task queue sched
#include <asm/atomic.h>
#include "cpqfcTSioctl.h"

/* FIXME - this is crap */
#define DbgDelay(secs) { int wait_time; printk( " DbgDelay %ds ", secs); \
                         for( wait_time=jiffies + (secs*HZ); \
		         time_before(jiffies, wait_time) ;) ; }

#define CPQFCTS_DRIVER_VER(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
/* don't forget to also change MODULE_DESCRIPTION in cpqfcTSinit.c */
#define VER_MAJOR 2
#define VER_MINOR 1
#define VER_SUBMINOR 2

/*
 *	Macros for kernel (esp. SMP) tracing using a PCI analyzer
 *	(e.g. x86).
 */
 
//#define PCI_KERNEL_TRACE
#ifdef PCI_KERNEL_TRACE
#define PCI_TRACE(x)		inl( fcChip->Registers.IOBaseL +x);
#define PCI_TRACEO(x,y) 	outl( x, (fcChip->Registers.IOBaseL +y));
#else

#define PCI_TRACE(x)
#define PCI_TRACEO(x,y)
#endif


//#define DEBUG_CMND		1   // debug output for Linux Scsi CDBs
//#define DUMMYCMND_DBG		1

//#define DEBUG_CPQFCTS 1
//#undef DEBUG_CPQFCTS 
#ifdef DEBUG_CPQFCTS
#define ENTER(x)		printk("cpqfcts : entering %s()\n", x);
#define LEAVE(x)		printk("cpqfcts : leaving %s()\n", x);
#define DEBUG(x)		x
#else
#define ENTER(x)
#define LEAVE(x)
#define DEBUG(x)
#endif				/* DEBUG_CPQFCTS */

//#define DEBUG_CPQFCTS_PCI	1
//#undef DEBUG_CPQFCTS_PCI
#if DEBUG_CPQFCTS_PCI
#define DEBUG_PCI(x)		x
#else
#define DEBUG_PCI(x)
#endif				/* DEBUG_CPQFCTS_PCI */

#define STACHLITE66_TS12	"Compaq FibreChannel HBA Tachyon TS HPFC-5166A/1.2"
#define STACHLITE66_TS13	"Compaq FibreChannel HBA Tachyon TS HPFC-5166A/1.3"
#define STACHLITE_UNKNOWN	"Compaq FibreChannel HBA Tachyon Chip/Board Ver??"
#define SAGILENT_XL2_21		"Agilent FC HBA, Tachyon XL2 HPFC-5200B/2.1"

// PDA is Peripheral Device Address, VSA is Volume Set Addressing
// Linux SCSI parameters
#define CPQFCTS_MAX_TARGET_ID	64

// Note, changing CPQFCTS_MAX_LUN to less than 32 (e.g, 8) will result in
// strange behavior if a box with more than, e.g. 8, is on the loop.
#define CPQFCTS_MAX_LUN		32	// The RA-4x00 supports 32 (Linux SCSI supports 8)
#define CPQFCTS_MAX_CHANNEL 	0	// One FC port on cpqfcTS HBA

#define CPQFCTS_CMD_PER_LUN	15	// power of 2 -1, must be >0
#define CPQFCTS_REQ_QUEUE_LEN	(TACH_SEST_LEN/2)	// must be < TACH_SEST_LEN

/* FIMXME - these are crpa too */
#define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s))
#ifndef DECLARE_MUTEX_LOCKED
#define DECLARE_MUTEX_LOCKED(sem) struct semaphore sem = MUTEX_LOCKED
#endif

#define DEV_NAME "cpqfcTS"

struct SupportedPCIcards {
	__u16 vendor_id;
	__u16 device_id;
};

/*
 *	nn:nn denotes bit field
 *	TachyonHeader struct def.
 *	the fields shared with ODB
 *	need to have same value
 */
 
/*
 * macro for FC-PH reject codes
 * payload format for LS_RJT (FC payloads are big endian):
 *     byte  0         1         2         3  (MSB)
 * DWORD 0   01        00        00        00
 * DWORD 1   resvd     code      expl.     vendor
 */
#define LS_RJT_REASON( code, expl) (( code<<8) | (expl <<16))

#define TachLiteSTATUS 0x12

/*
 *	Fibre Channel EXCHANGE status codes for Tachyon chips/ driver software
 *	32-bit ERROR word defines
 */
#define INVALID_ARGS 		0x1
#define LNKDWN_OSLS  		0x2
#define LNKDWN_LASER 		0x4
#define OUTQUE_FULL  		0x8
#define DRIVERQ_FULL 		0x10
#define SEST_FULL    		0x20
#define BAD_ALPA     		0x40
#define OVERFLOW     		0x80		// inbound CM
#define COUNT_ERROR     	0x100		// inbound CM
#define LINKFAIL_RX     	0x200		// inbound CM
#define ABORTSEQ_NOTIFY 	0x400		// outbound CM
#define LINKFAIL_TX     	0x800		// outbound CM
#define HOSTPROG_ERR     	0x1000		// outbound CM
#define FRAME_TO         	0x2000		// outbound CM
#define INV_ENTRY        	0x4000		// outbound CM
#define SESTPROG_ERR     	0x8000		// outbound CM
#define OUTBOUND_TIMEOUT 	0x10000L	// timeout waiting for Tachyon outbound CM
#define INITIATOR_ABORT  	0x20000L	// initiator exchange timeout or O/S ABORT
#define MEMPOOL_FAIL     	0x40000L	// O/S memory pool allocation failed
#define FC2_TIMEOUT      	0x80000L	// driver timeout for lost frames
#define TARGET_ABORT     	0x100000L	// ABTS received from FC port
#define EXCHANGE_QUEUED  	0x200000L	// e.g. Link State was LDn on fcStart
#define PORTID_CHANGED   	0x400000L	// fc Port address changed
#define DEVICE_REMOVED   	0x800000L	// fc Port address changed
/*
 *	Several error scenarios result in SEST Exchange frames 
 *	unexpectedly arriving in the SFQ
 */
#define SFQ_FRAME		0x1000000L	// SFQ frames from open Exchange

/*
 *	Maximum number of Host Bus Adapters (HBA) / controllers supported
 *	only important for mem allocation dimensions - increase as necessary
 */
 
#define MAX_ADAPTERS 8
#define MAX_RX_PAYLOAD 1024			// hardware dependent max frame payload

/*
 *	Tach header struct defines
 */

#define SOFi3			0x7
#define SOFf			0x8
#define SOFn3			0xB
#define EOFn			0x5
#define EOFt			0x6

// FCP R_CTL defines
#define FCP_CMND		0x6
#define FCP_XFER_RDY		0x5
#define FCP_RSP			0x7
#define FCP_RESPONSE		0x777		// (arbitrary #)
#define NEED_FCP_RSP		0x77		// (arbitrary #)
#define FCP_DATA		0x1

#define RESET_TACH 		0x100		// Reset Tachyon/TachLite
#define SCSI_IWE 		0x2000		// initiator write entry (for SEST)
#define SCSI_IRE 		0x3000		// initiator read entry (for SEST)
#define SCSI_TRE 		0x400		// target read entry (for SEST)
#define SCSI_TWE 		0x500		// target write entry (for SEST)
#define TOGGLE_LASER 		0x800
#define LIP			0x900
#define CLEAR_FCPORTS		99		// (arbitrary #) free mem for Logged in ports
#define FMINIT			0x707		// (arbitrary) for Frame Manager Init command

/*
 *	BLS == Basic Link Service
 *	ELS == Extended Link Service
 */
 
#define BLS_NOP 		4
#define BLS_ABTS		0x10		// FC-PH Basic Link Service Abort Sequence
#define BLS_ABTS_ACC		0x100		// FC-PH Basic Link Service Abort Sequence Accept
#define BLS_ABTS_RJT		0x101		// FC-PH Basic Link Service Abort Sequence Reject
#define ELS_PLOGI		0x03		// FC-PH Port Login (arbitrary assign)
#define ELS_SCR			0x70		// (arb assign) State Change Registration (Fabric)
#define FCS_NSR			0x72		// (arb assign) Name Service Request (Fabric)
#define ELS_FLOGI		0x44		// (arb assign) Fabric Login
#define ELS_FDISC		0x41		// (arb assign) Fabric Discovery (Login)
#define ELS_PDISC		0x50		// FC-PH2 Port Discovery
#define ELS_ABTX		0x06		// FC-PH Abort Exchange
#define ELS_LOGO		0x05		// FC-PH Port Logout
#define ELS_PRLI		0x20		// FCP-SCSI Process Login
#define ELS_PRLO		0x21		// FCP-SCSI Process Logout
#define ELS_LOGO_ACC		0x07		// {FC-PH} Port Logout Accept
#define ELS_PLOGI_ACC		0x08		// {FC-PH} Port Login Accept
#define ELS_ACC			0x18		// {FC-PH} (generic) ACCept
#define ELS_PRLI_ACC		0x22		// {FCP-SCSI} Process Login Accept
#define ELS_RJT			0x1000000
#define SCSI_REPORT_LUNS	0x0A0
#define FCP_TARGET_RESET	0x200

#define ELS_LILP_FRAME		0x00000711	// 1st payload word of LILP frame

#define SFQ_UNASSISTED_FCP	1		// ICM, DWord3, "Type" unassisted FCP
#define SFQ_UNKNOWN      	0x31		// (arbitrary) ICM, DWord3, "Type" unknown

/*
 * These "LINK" bits refer to loop or non-loop
 */
#define LINKACTIVE		0x2		// fcLinkQ type - LINK UP Tachyon FM 'Lup' bit set
#define LINKDOWN		0xf2		// fcLinkQ type - LINK DOWN Tachyon FM 'Ldn' bit set

//#define VOLUME_SET_ADDRESSING 1 // "channel" or "bus" 1

typedef struct			// 32 bytes hdr ONLY (e.g. FCP_DATA buffer for SEST)
{
	__u32 reserved;		// dword 0 (don't use)
	__u32 sof_eof;
	__u32 d_id;		// dword 2 - 31:24 R_CTL, 23:0 D_ID
	__u32 s_id;		// dword 3 - 31:24 CS_CTL, 23:0 S_ID
	__u32 f_ctl;		// dword 4 - 31:24 Type,  23:0 F_CTL
	__u32 seq_cnt;		// dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
	__u32 ox_rx_id;		// dword 6 - 31:16 OX_ID,  15:0 RX_ID
	__u32 ro;		// dword 7 - relative offset
} TachFCHDR;

				// NOTE!! the following struct MUST be 64 bytes.
typedef struct			// 32 bytes hdr + 32 bytes payload
{
	__u32 reserved;		// dword 0 (don't use - must clear to 0)
	__u32 sof_eof;		// dword 1 - 31:24 SOF:EOF, UAM,CLS, LCr, TFV, TimeStamp
	__u32 d_id;		// dword 2 - 31:24 R_CTL, 23:0 D_ID
	__u32 s_id;		// dword 3 - 31:24 CS_CTL, 23:0 S_ID
	__u32 f_ctl;		// dword 4 - 31:24 Type,  23:0 F_CTL
	__u32 seq_cnt;		// dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
	__u32 ox_rx_id;		// dword 6 - 31:16 OX_ID,  15:0 RX_ID
	__u32 ro;		// dword 7 - relative offset
//---------
	__u32 pl[8];		// dwords 8-15 frame data payload
} TachFCHDR_CMND;


typedef struct			// 32 bytes hdr + 120 bytes payload
{
	__u32 reserved;		// dword 0 (don't use - must clear to 0)
	__u32 sof_eof;		// dword 1 - 31:24 SOF:EOF, UAM,CLS, LCr, TFV, TimeStamp
	__u32 d_id;		// dword 2 - 31:24 R_CTL, 23:0 D_ID
	__u32 s_id;		// dword 3 - 31:24 CS_CTL, 23:0 S_ID
	__u32 f_ctl;		// dword 4 - 31:24 Type,  23:0 F_CTL
	__u32 seq_cnt;		// dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
	__u32 ox_rx_id;		// dword 6 - 31:16 OX_ID,  15:0 RX_ID
	__u32 ro;		// dword 7 - relative offset
//---------
	__u32 pl[30];		// largest necessary payload (for LOGIN cmnds)
} TachFCHDR_GCMND;

typedef struct			// 32 bytes hdr + 64 bytes payload
{
	__u32 reserved;		// dword 0 (don't use)
	__u32 sof_eof;
	__u32 d_id;		// dword 2 - 31:24 R_CTL, 23:0 D_ID
	__u32 s_id;		// dword 3 - 31:24 CS_CTL, 23:0 S_ID
	__u32 f_ctl;		// dword 4 - 31:24 Type,  23:0 F_CTL
	__u32 seq_cnt;		// dword 5 - 31:24 SEQ_ID, 23:16 DF_CTL, 15:0 SEQ_CNT
	__u32 ox_rx_id;		// dword 6 - 31:16 OX_ID,  15:0 RX_ID
	__u32 ro;		// dword 7 - relative offset
//---------
	__u32 pl[18];		// payload for FCP-RSP (response buffer) RA-4x00 is 72bytes
} TachFCHDR_RSP;






// Inbound Message Queue structures...
typedef struct			// each entry 8 words (32 bytes)
{
	__u32 type;		// IMQ completion message types
	__u32 word[7];		// remainder of structure
				// interpreted by IMQ type
} TachyonIMQE;


// Queues for TachLite not in original Tachyon
// ERQ       - Exchange Request Queue (for outbound commands)
// SFQ       - Single Frame Queue (for incoming frames)

				// Define Tachyon Outbound Command Que
				// (Since many Tachyon registers are Read
				// only, maintain copies for debugging)
				// most Tach ques need power-of-2 sizes,
				// where registers are loaded with po2 -1
#define TACH_SEST_LEN 512	// TachLite SEST

#define ELS_EXCHANGES 64	// e.g. PLOGI, RSCN, ...
// define the total number of outstanding (simultaneous) exchanges
#define TACH_MAX_XID (TACH_SEST_LEN + ELS_EXCHANGES)	// ELS exchanges

#define ERQ_LEN 128		// power of 2, max 4096

// Inbound Message Queue structures...
#define IMQ_LEN 512		// minimum 4 entries [(power of 2) - 1]
typedef struct			// 8 words - 32 bytes
{
	TachyonIMQE QEntry[IMQ_LEN];
	__u32 producerIndex;	// IMQ Producer Index register
	// @32 byte align
	__u32 consumerIndex;	// Consumer Index register (in Tachyon)
	__u32 length;		// Length register
	__u32 base;
} TachyonIMQ;			// @ 32 * IMQ_LEN align



typedef struct			// inbound completion message
{
	__u32 Type;
	__u32 Index;
	__u32 TransferLength;
} TachyonInbCM;



// arbitrary numeric tags for TL structures
#define TL_FCHS 1		// TachLite Fibre Channel Header Structure
#define TL_IWE 2		// initiator write entry (for SEST)
#define TL_TWE 3		// target write entry (for SEST)
#define TL_IRE 4		// initiator read entry (for SEST)
#define TL_TRE 5		// target read entry (for SEST)
#define TL_IRB 6		// I/O request block

				// for INCOMING frames
#define SFQ_LEN 32		// minimum 32 entries, max 4096

typedef struct			// Single Frame Que
{
	TachFCHDR_CMND QEntry[SFQ_LEN];	// must be 64 bytes!!
	__u32 producerIndex;	// IMQ Producer Index register
	// @32 byte align
	__u32 consumerIndex;	// Consumer Index register (in Tachyon)
	__u32 length;		// Length register
	__u32 base;
} TachLiteSFQ;


typedef struct			// I/O Request Block flags
{
	__u8 BRD:1;
	 __u8:1;		// reserved
	__u8 SFA:1;
	__u8 DNC:1;
	__u8 DIN:1;
	__u8 DCM:1;
	__u8 CTS:1;
	__u8 SBV:1;		// IRB entry valid - IRB'B' only
} IRBflags;

typedef struct			// I/O Request Block
{				// Request 'A'
	__u32 Req_A_SFS_Len;	// total frame len (hdr + payload), min 32
	__u32 Req_A_SFS_Addr;	// 32-bit pointer to FCHS struct (to be sent)
	__u32 Req_A_SFS_D_ID;	// 24-bit FC destination (i.e. 8 bit al_pa)
	__u32 Req_A_Trans_ID;	// X_ID (OX_ID or RX_ID) and/or Index in SEST
	// Request 'B'
	__u32 Req_B_SFS_Len;	// total frame len (hdr + payload), min 32
	__u32 Req_B_SFS_Addr;	// 32-bit pointer to FCHS struct (to be sent)
	__u32 Req_B_SFS_D_ID;	// 24-bit FC destination (i.e. 8 bit al_pa)
	__u32 Req_B_Trans_ID;	// X_ID (OX_ID or RX_ID) and/or Index in SEST
} TachLiteIRB;


typedef struct			// TachLite placeholder for IRBs
{				// aligned @sizeof(ERQ) for TachLite
	// MAX commands is sum of SEST len and ERQ
	// we know that each SEST entry requires an
	// IRB (ERQ) entry; in addition, we provide
	// ERQ_LEN
	TachLiteIRB QEntry[ERQ_LEN];	// Base register; entries 32 bytes ea.
	__u32 consumerIndex;	// Consumer Index register
	__u32 producerIndex;	// ERQ Producer Index register
	__u32 length;		// Length register
	__u32 base;		// copy of base ptr for debug
	// struct is sized for largest expected cmnd (LOGIN)
} TachLiteERQ;

// for now, just 32 bit DMA, eventually 40something, with code changes
#define CPQFCTS_DMA_MASK ((unsigned long) (0x00000000FFFFFFFF))

#define TL_MAX_SG_ELEM_LEN 0x7ffff	// Max buffer length a single S/G entry
					// may represent (a hardware limitation).  The
					// only reason to ever change this is if you
					// want to exercise very-hard-to-reach code in
					// cpqfcTSworker.c:build_SEST_sglist().

#define TL_DANGER_SGPAGES 7	// arbitrary high water mark for # of S/G pages
				// we must exceed to elicit a warning indicative
				// of EXTREMELY large data transfers or 
				// EXTREME memory fragmentation.
				// (means we just used up 2048 S/G elements,
				// Never seen this is real life, only in 
				// testing with tricked up driver.)

#define TL_EXT_SG_PAGE_COUNT 256	// Number of Extended Scatter/Gather a/l PAIRS
					// Tachyon register (IOBaseU 0x68)
					// power-of-2 value ONLY!  4 min, 256 max

			  // byte len is #Pairs * 2 __u32/Pair * 4 bytes/__u32
#define TL_EXT_SG_PAGE_BYTELEN (TL_EXT_SG_PAGE_COUNT *2 *4)



// SEST entry types: IWE, IRE, TWE, TRE
typedef struct {
	__u32 Hdr_Len;
	__u32 Hdr_Addr;
	__u32 RSP_Len;
	__u32 RSP_Addr;
	__u32 Buff_Off;
#define USES_EXTENDED_SGLIST(this_sest, x_ID) \
	(!((this_sest)->u[ x_ID ].IWE.Buff_Off & 0x80000000))
	__u32 Link;
	__u32 RX_ID;
	__u32 Data_Len;
	__u32 Exp_RO;
	__u32 Exp_Byte_Cnt;
	// --- extended/local Gather Len/Address pairs
	__u32 GLen1;
	__u32 GAddr1;
	__u32 GLen2;
	__u32 GAddr2;
	__u32 GLen3;
	__u32 GAddr3;
} TachLiteIWE;


typedef struct {
	__u32 Seq_Accum;
	__u32 reserved;		// must clear to 0
	__u32 RSP_Len;
	__u32 RSP_Addr;
	__u32 Buff_Off;
	__u32 Buff_Index;	// __u32 5
	__u32 Exp_RO;
	__u32 Byte_Count;
	__u32 reserved_;	// __u32 8
	__u32 Exp_Byte_Cnt;
	// --- extended/local Scatter Len/Address pairs
	__u32 SLen1;
	__u32 SAddr1;
	__u32 SLen2;
	__u32 SAddr2;
	__u32 SLen3;
	__u32 SAddr3;
} TachLiteIRE;


typedef struct			// Target Write Entry
{
	__u32 Seq_Accum;	// dword 0
	__u32 reserved;		// dword 1  must clear to 0
	__u32 Remote_Node_ID;
	__u32 reserved1;	// dword 3  must clear to 0
	__u32 Buff_Off;
	__u32 Buff_Index;	// __u32 5
	__u32 Exp_RO;
	__u32 Byte_Count;
	__u32 reserved_;	// __u32 8
	__u32 Exp_Byte_Cnt;
	// --- extended/local Scatter Len/Address pairs
	__u32 SLen1;
	__u32 SAddr1;
	__u32 SLen2;
	__u32 SAddr2;
	__u32 SLen3;
	__u32 SAddr3;
} TachLiteTWE;

typedef struct {
	__u32 Hdr_Len;
	__u32 Hdr_Addr;
	__u32 RSP_Len;		// DWord 2
	__u32 RSP_Addr;
	__u32 Buff_Off;
	__u32 Buff_Index;	// DWord 5
	__u32 reserved;
	__u32 Data_Len;
	__u32 reserved_;
	__u32 reserved__;
	// --- extended/local Gather Len/Address pairs
	__u32 GLen1;		// DWord A
	__u32 GAddr1;
	__u32 GLen2;
	__u32 GAddr2;
	__u32 GLen3;
	__u32 GAddr3;
} TachLiteTRE;

typedef struct ext_sg_page_ptr_t *PSGPAGES;
typedef struct ext_sg_page_ptr_t {
	unsigned char page[TL_EXT_SG_PAGE_BYTELEN * 2];	// 2x for alignment
	dma_addr_t busaddr;	// need the bus addresses and
	unsigned int maplen;	// lengths for later pci unmapping.
	PSGPAGES next;
} SGPAGES;			// linked list of S/G pairs, by Exchange

typedef struct			// SCSI Exchange State Table
{
	union			// Entry can be IWE, IRE, TWE, TRE
	{			// 64 bytes per entry
		TachLiteIWE IWE;
		TachLiteIRE IRE;
		TachLiteTWE TWE;
		TachLiteTRE TRE;
	} u[TACH_SEST_LEN];

	TachFCHDR DataHDR[TACH_SEST_LEN];	// for SEST FCP_DATA frame hdr (no pl)
	TachFCHDR_RSP RspHDR[TACH_SEST_LEN];	// space for SEST FCP_RSP frame
	PSGPAGES sgPages[TACH_SEST_LEN];	// head of linked list of Pool-allocations
	__u32 length;		// Length register
	__u32 base;		// copy of base ptr for debug
} TachSEST;



typedef struct			// each register has it's own address
				// and value (used for write-only regs)
{
	void *address;
	volatile __u32 value;
} FCREGISTER;

typedef struct			// Host copy - TachLite Registers
{
	__u32 IOBaseL, IOBaseU;	// I/O port lower and upper TL register addresses
	__u32 MemBase;		// memory mapped register addresses
	void *ReMapMemBase;	// O/S VM reference for MemBase
	__u32 wwn_hi;		// WWN is set once at startup
	__u32 wwn_lo;
	__u32 my_al_pa;		// al_pa received after LIP()
	__u32 ROMCTR;		// flags for on-board RAM/ROM
	__u32 RAMBase;		// on-board RAM (i.e. some Tachlites)
	__u32 SROMBase;		// on-board EEPROM (some Tachlites)
	__u32 PCIMCTR;		// PCI Master Control Reg (has bus width)

	FCREGISTER INTEN;	// copy of interrupt enable mask
	FCREGISTER INTPEND;	// interrupt pending
	FCREGISTER INTSTAT;	// interrupt status
	FCREGISTER SFQconsumerIndex;
	FCREGISTER ERQproducerIndex;
	FCREGISTER TYconfig;	// TachYon (chip level)
	FCREGISTER TYcontrol;
	FCREGISTER TYstatus;
	FCREGISTER FMconfig;	// Frame Manager (FC loop level)
	FCREGISTER FMcontrol;
	FCREGISTER FMstatus;
	FCREGISTER FMLinkStatus1;
	FCREGISTER FMLinkStatus2;
	FCREGISTER FMBB_CreditZero;
	FCREGISTER status;
	FCREGISTER ed_tov;	// error detect time-out value
	FCREGISTER rcv_al_pa;	// received arb. loop physical address
	FCREGISTER primitive;	// e.g. LIP(), OPN(), ...
} TL_REGISTERS;



typedef struct {
	__u32 ok;
	__u32 invalidArgs;
	__u32 linkDown;
	__u32 linkUp;
	__u32 outQueFull;
	__u32 SESTFull;
	__u32 hpe;		// host programming err (from Tach)
	__u32 FC4aborted;	// aborts from Application or upper driver layer
	__u32 FC2aborted;	// aborts from our driver's timeouts
	__u32 timeouts;		// our driver timeout (on individual exchanges)
	__u32 logouts;		// explicit - sent LOGO; implicit - device removed
	__u32 retries;
	__u32 linkFailTX;
	__u32 linkFailRX;
	__u32 CntErrors;	// byte count expected != count received (typ. SEST)
	__u32 e_stores;		// elastic store errs
	__u32 resets;		// hard or soft controller resets
	__u32 FMinits;		// TACH Frame Manager Init (e.g. LIPs)
	__u32 lnkQueFull;	// too many LOGIN, loop commands
	__u32 ScsiQueFull;	// too many FCP-SCSI inbound frames
	__u32 LossofSignal;	// FM link status 1 regs
	__u32 BadRXChar;	// FM link status 1 regs
	__u32 LossofSync;	// FM link status 1 regs
	__u32 Rx_EOFa;		// FM link status 2 regs (received EOFa)
	__u32 Dis_Frm;		// FM link status 2 regs (discarded frames)
	__u32 Bad_CRC;		// FM link status 2 regs
	__u32 BB0_Timer;	//  FM BB_Credit Zero Timer Reg
	__u32 loopBreaks;	// infinite loop exits
	__u32 lastBB0timer;	// static accum. buffer needed by Tachlite
} FCSTATS;


typedef struct			// Config Options
{				// LS Bit first
	__u16:1;		// bit0:
	__u16 flogi:1;		// bit1: We sent FLOGI - wait for Fabric logins
	__u16 fabric:1;	// bit2: Tachyon detected Fabric (FM stat LG)
	__u16 LILPin:1;	// bit3: We can use an FC-AL LILP frame
	__u16 target:1;	// bit4: this Port has SCSI target capability
	__u16 initiator:1;	// bit5: this Port has SCSI initiator capability
	__u16 extLoopback:1;	// bit6: loopback at GBIC
	__u16 intLoopback:1;	// bit7: loopback in HP silicon
	 __u16:1;		// bit8:
	 __u16:1;		// bit9:
	 __u16:1;		// bit10:
	 __u16:1;		// bit11:
	 __u16:1;		// bit12:
	 __u16:1;		// bit13:
	 __u16:1;		// bit14:
	 __u16:1;		// bit15:
} FC_OPTIONS;



typedef struct dyn_mem_pair {
	void *BaseAllocated;	// address as allocated from O/S;
	unsigned long AlignedAddress;	// aligned address (used by Tachyon DMA)
	dma_addr_t dma_handle;
	size_t size;
} ALIGNED_MEM;




// these structs contain only CRUCIAL (stuff we actually use) parameters
// from FC-PH(n) logins.  (Don't save entire LOGIN payload to save mem.)

// Implicit logout happens when the loop goes down - we require PDISC
// to restore.  Explicit logout is when WE decide never to talk to someone,
// or when a target refuses to talk to us, i.e. sends us a LOGO frame or
// LS_RJT reject in response to our PLOGI request.

#define IMPLICIT_LOGOUT 1
#define EXPLICIT_LOGOUT 2

typedef struct {
	__u8 channel;		// SCSI "bus"
	__u8 target;
	__u8 InqDeviceType;	// byte 0 from SCSI Inquiry response
	__u8 VolumeSetAddressing;	// FCP-SCSI LUN coding (40h for VSA)
	__u8 LunMasking;	// True if selective presentation supported
	__u8 lun[CPQFCTS_MAX_LUN];
} SCSI_NEXUS;


typedef struct {
	union {
		__u8 ucWWN[8];	// a FC 64-bit World Wide Name/ PortID of target
		// addressing of single target on single loop...
		u64 liWWN;
	} u;

	__u32 port_id;		// a FC 24-bit address of port (lower 8 bits = al_pa)

	Scsi_Cmnd ScsiCmnd;	// command buffer for Report Luns
#define REPORT_LUNS_PL 256
	__u8 ReportLunsPayload[REPORT_LUNS_PL];

	SCSI_NEXUS ScsiNexus;	// LUNs per FC device

	__u32 LOGO_counter;	// might try several times before logging out for good
	__u32 LOGO_timer;	// after LIP, ports expecting PDISC must time-out and
	// LOGOut if successful PDISC not completed in 2 secs

	__u32 concurrent_seq;	// must be 1 or greater
	__u32 rx_data_size;	// e.g. 128, 256, 1024, 2048 per FC-PH spec
	__u32 BB_credit;
	__u32 EE_credit;

	__u32 fcp_info;		// from PRLI (i.e. INITIATOR/ TARGET flags)
	// flags for login process
	__u8 Originator;	// Login sequence Originated (if false, we
	// responded to another port's login sequence)
	__u8 plogi;		// PLOGI frame ACCepted (originated or responded)
	__u8 pdisc;		// PDISC frame was ORIGINATED (self-login logic)
	__u8 prli;		// PRLI frame ACCepted (originated or responded)
	__u8 flogi;		// FLOGI frame ACCepted (originated or responded)
	__u8 logo;		// port permanently logged out (invalid login param)
	__u8 flogiReq;	// Fabric login required (set in LIP process)
	__u8 highest_ver;
	__u8 lowest_ver;


	// when the "target" (actually FC Port) is waiting for login
	// (e.g. after Link reset), set the device_blocked bit;
	// after Port completes login, un-block target.
	__u8 device_blocked;	// see Scsi_Device struct

	// define singly-linked list of logged-in ports
	// once a port_id is identified, it is remembered,
	// even if the port is removed indefinitely
	void * pNextPort;	// actually, type PFC_LOGGEDIN_PORT; void for Compiler

} FC_LOGGEDIN_PORT, *PFC_LOGGEDIN_PORT;



// This serves as the ESB (Exchange Status Block),
// and has timeout counter; used for ABORTs
typedef struct {		// FC-1 X_IDs
	__u32 type;		// ELS_PLOGI, SCSI_IWE, ... (0 if free)
	PFC_LOGGEDIN_PORT pLoggedInPort;	// FC device on other end of Exchange
	Scsi_Cmnd *Cmnd;	// Linux SCSI command packet includes S/G list
	__u32 timeOut;		// units of ??, DEC by driver, Abort when 0
	__u32 reTries;		// need one or more retries?
	__u32 status;		// flags indicating errors (0 if none)
	TachLiteIRB IRB;	// I/O Request Block, gets copied to ERQ
	TachFCHDR_GCMND fchs;	// location of IRB's Req_A_SFS_Addr
} FC_EXCHANGE, *PFC_EXCHANGE;

// Unfortunately, Linux limits our kmalloc() allocations to 128k.
// Because of this and the fact that our ScsiRegister allocation
// is also constrained, we move this large structure out for
// allocation after Scsi Register.
// (In other words, this cumbersome indirection is necessary
// because of kernel memory allocation constraints!)

typedef struct			// we will allocate this dynamically
{
	FC_EXCHANGE fcExchange[TACH_MAX_XID];
} FC_EXCHANGES;











typedef struct {
	char Name[64];		// name of controller ("HP Tachlite TL Rev2.0, 33MHz, 64bit bus")
	//void *  pAdapterDevExt; // back pointer to device object/extension
	__u32 ChipType;		// local numeric key for Tachyon Type / Rev.
	__u32 status;		// our Driver - logical status

	TL_REGISTERS Registers;	// reg addresses & host memory copies
	// FC-4 mapping of 'transaction' to X_IDs
	__u8 LILPmap[32 * 4];	// Loop Position Map of ALPAs (late FC-AL only)
	FC_OPTIONS Options;	// e.g. Target, Initiator, loopback...
	__u8 highest_FCPH_ver;	// FC-PH version limits
	__u8 lowest_FCPH_ver;	// FC-PH version limits

	FC_EXCHANGES *Exchanges;
	__u32 fcLsExchangeLRU;	// Least Recently Used counter (Link Service)
	__u32 fcSestExchangeLRU;	// Least Recently Used counter (FCP-SCSI)
	FC_LOGGEDIN_PORT fcPorts;	// linked list of every FC port ever seen
	FCSTATS fcStats;	// FC comm err counters

	// Host memory QUEUE pointers
	TachLiteERQ *ERQ;	// Exchange Request Que 
	TachyonIMQ *IMQ;	// Inbound Message Que 
	TachLiteSFQ *SFQ;	// Single Frame Queue
	TachSEST *SEST;		// SCSI Exchange State Table

	dma_addr_t exch_dma_handle;

	// these function pointers are for "generic" functions, which are
	// replaced with Host Bus Adapter types at
	// runtime.
	int (*CreateTachyonQues) (void *, int);
	int (*DestroyTachyonQues) (void *, int);
	int (*LaserControl) (void *, int);	// e.g. On/Off
	int (*ResetTachyon) (void *, int);
	void (*FreezeTachyon) (void *, int);
	void (*UnFreezeTachyon) (void *, int);
	int (*InitializeTachyon) (void *, int, int);
	int (*InitializeFrameManager) (void *, int);
	int (*ProcessIMQEntry) (void *);
	int (*ReadWriteWWN) (void *, int ReadWrite);
	int (*ReadWriteNVRAM) (void *, void *, int ReadWrite);

} TACHYON, *PTACHYON;


void cpqfcTSClearLinkStatusCounters(TACHYON * fcChip);

int CpqTsCreateTachLiteQues(void *pHBA, int opcode);
int CpqTsDestroyTachLiteQues(void *, int);
int CpqTsInitializeTachLite(void *pHBA, int opcode1, int opcode2);

int CpqTsProcessIMQEntry(void *pHBA);
int CpqTsResetTachLite(void *pHBA, int type);
void CpqTsFreezeTachlite(void *pHBA, int type);
void CpqTsUnFreezeTachlite(void *pHBA, int type);
int CpqTsInitializeFrameManager(void *pHBA, int);
int CpqTsLaserControl(void *addrBase, int opcode);
int CpqTsReadWriteWWN(void *, int ReadWrite);
int CpqTsReadWriteNVRAM(void *, void *data, int ReadWrite);

void cpqfcTS_WorkTask(struct Scsi_Host *HostAdapter);
void cpqfcTSWorkerThread(void *host);

int cpqfcTS_GetNVRAM_data(__u8 * wwnbuf, __u8 * buf);
__u32 cpqfcTS_ReadNVRAM(void *GPIOin, void *GPIOout, __u16 count, __u8 * buf);

__u8 tl_write_i2c_nvram(void *GPIOin, void *GPIOout, __u16 startOffset,	// e.g. 0x2f for WWN start
			   __u16 count, __u8 * buf);


// define misc functions 
int cpqfcTSGetLPSM(PTACHYON fcChip, char cErrorString[]);
int cpqfcTSDecodeGBICtype(PTACHYON fcChip, char cErrorString[]);
void *fcMemManager(struct pci_dev *pdev, ALIGNED_MEM * dyn_mem_pair, __u32 n_alloc, __u32 ab, __u32 ulAlignedAddress, dma_addr_t * dma_handle);

void BigEndianSwap(__u8 * source, __u8 * dest, __u16 cnt);

//__u32 virt_to_phys( void * virtaddr );


// Linux interrupt handler
void cpqfcTS_intr_handler(int irq, void *dev_id, struct pt_regs *regs);
void cpqfcTSheartbeat(unsigned long ptr);



// The biggest Q element we deal with is Aborts - we
// need 4 bytes for x_ID, and a Scsi_Cmnd (~284 bytes)
//#define LINKQ_ITEM_SIZE ((4+sizeof(Scsi_Cmnd)+3)/4)
#define LINKQ_ITEM_SIZE (3*16)
typedef struct {
	__u32 Type;		// e.g. LINKUP, SFQENTRY, PDISC, BLS_ABTS, ...
	__u32 ulBuff[LINKQ_ITEM_SIZE];
} LINKQ_ITEM;

#define FC_LINKQ_DEPTH TACH_MAX_XID
typedef struct {
	__u32 producer;
	__u32 consumer;		// when producer equals consumer, Q empty

	LINKQ_ITEM Qitem[FC_LINKQ_DEPTH];

} FC_LINK_QUE, *PFC_LINK_QUE;


     // DPC routines post to here on Inbound SCSI frames
     // User thread processes
#define FC_SCSIQ_DEPTH 32

typedef struct {
	int Type;		// e.g. SCSI
	__u32 ulBuff[3 * 16];
} SCSIQ_ITEM;

typedef struct {
	__u32 producer;
	__u32 consumer;		// when producer equals consumer, Q empty

	SCSIQ_ITEM Qitem[FC_SCSIQ_DEPTH];

} FC_SCSI_QUE, *PFC_SCSI_QUE;





#define DYNAMIC_ALLOCATIONS 4	// Tachyon aligned allocations: ERQ,IMQ,SFQ,SEST

// Linux space allocated per HBA (chip state, etc.)
typedef struct {
	struct Scsi_Host *HostAdapter;	// back pointer to Linux Scsi struct

	TACHYON fcChip;		// All Tachyon registers, Queues, functions
	ALIGNED_MEM dynamic_mem[DYNAMIC_ALLOCATIONS];

	struct pci_dev *PciDev;
	dma_addr_t fcLQ_dma_handle;

	Scsi_Cmnd *LinkDnCmnd[CPQFCTS_REQ_QUEUE_LEN];	// collects Cmnds during LDn
	// (for Acceptable targets)
	Scsi_Cmnd *BoardLockCmnd[CPQFCTS_REQ_QUEUE_LEN];	// SEST was full

	Scsi_Cmnd *BadTargetCmnd[CPQFCTS_MAX_TARGET_ID];	// missing targets

	u_char HBAnum;		// 0-based host number


	struct timer_list cpqfcTStimer;	// FC utility timer for implicit
	// logouts, FC protocol timeouts, etc.
	int fcStatsTime;	// Statistics delta reporting time

	struct task_struct *worker_thread;	// our kernel thread
	int PortDiscDone;	// set by SendLogins(), cleared by LDn

	struct semaphore *TachFrozen;
	struct semaphore *TYOBcomplete;	// handshake for Tach outbound frames
	struct semaphore *fcQueReady;	// FibreChannel work for our kernel thread
	struct semaphore *notify_wt;	// synchronizes kernel thread kill
	struct semaphore *BoardLock;

	PFC_LINK_QUE fcLQ;	// the WorkerThread operates on this

	spinlock_t hba_spinlock;	// held/released by WorkerThread

} CPQFCHBA;

#define	CPQ_SPINLOCK_HBA( x )   spin_lock(&x->hba_spinlock);
#define CPQ_SPINUNLOCK_HBA(x)   spin_unlock(&x->hba_spinlock);



void cpqfcTSImplicitLogout(CPQFCHBA * cpqfcHBAdata, PFC_LOGGEDIN_PORT pFcPort);


void cpqfcTSTerminateExchange(CPQFCHBA *, SCSI_NEXUS * target, int);

PFC_LOGGEDIN_PORT fcPortLoggedIn(CPQFCHBA * cpqfcHBAdata, TachFCHDR_GCMND * fchs, __u8, __u8);
void fcProcessLoggedIn(CPQFCHBA * cpqfcHBAdata, TachFCHDR_GCMND * fchs);


__u32 cpqfcTSBuildExchange(CPQFCHBA * cpqfcHBAdata, __u32 type,	// e.g. PLOGI
			   TachFCHDR_GCMND * InFCHS,	// incoming FCHS
			   void *Data,	// the CDB, scatter/gather, etc.  
			   __s32 * ExchangeID);	// allocated exchange ID

__u32 cpqfcTSStartExchange(CPQFCHBA * cpqfcHBAdata, __s32 ExchangeID);

void cpqfcTSCompleteExchange(struct pci_dev *pcidev, PTACHYON fcChip, __u32 exchange_ID);


PFC_LOGGEDIN_PORT fcFindLoggedInPort(PTACHYON fcChip, Scsi_Cmnd * Cmnd,	// (We want the channel/target/lun Nexus from Cmnd)
				     __u32 port_id,	// search linked list for al_pa, or
				     __u8 wwn[8],	// search linked list for WWN, or...
				     PFC_LOGGEDIN_PORT * pLastLoggedInPort);

void cpqfcTSPutLinkQue(CPQFCHBA * cpqfcHBAdata, int Type, void *QueContent);

void fcPutScsiQue(CPQFCHBA * cpqfcHBAdata, int Type, void *QueContent);

void fcLinkQReset(CPQFCHBA *);
void fcScsiQReset(CPQFCHBA *);
void fcSestReset(CPQFCHBA *);

void cpqfc_pci_unmap(struct pci_dev *pcidev, Scsi_Cmnd * cmd, PTACHYON fcChip, __u32 x_ID);

extern const __u8 valid_al_pa[];
extern const int number_of_al_pa;

#define FCP_RESID_UNDER   0x80000
#define FCP_RESID_OVER    0x40000
#define FCP_SNS_LEN_VALID 0x20000
#define FCP_RSP_LEN_VALID 0x10000

// RSP_CODE definitions (dpANS Fibre Channel Protocol for SCSI, pg 34)
#define FCP_DATA_LEN_NOT_BURST_LEN 0x1000000
#define FCP_CMND_FIELD_INVALID     0x2000000
#define FCP_DATA_RO_NOT_XRDY_RO    0x3000000
#define FCP_TASKFUNCTION_NS        0x4000000
#define FCP_TASKFUNCTION_FAIL      0x5000000

// FCP-SCSI response status struct
typedef struct			// see "TachFCHDR_RSP" definition - 64 bytes
{
	__u32 reserved;
	__u32 reserved1;
	__u32 fcp_status;	// field validity and SCSI status
	__u32 fcp_resid;
	__u32 fcp_sns_len;	// length of FCP_SNS_INFO field
	__u32 fcp_rsp_len;	// length of FCP_RSP_INFO field (expect 8)
	__u32 fcp_rsp_info;	// 4 bytes of FCP protocol response information
	__u32 fcp_rsp_info2;	// (4 more bytes, since most implementations use 8)
	__u8 fcp_sns_info[36];	// bytes for SCSI sense (ASC, ASCQ)

} FCP_STATUS_RESPONSE, *PFCP_STATUS_RESPONSE;


// Fabric State Change Registration
typedef struct scrpl {
	__u32 command;
	__u32 function;
} SCR_PL;

// Fabric Name Service Request
typedef struct nsrpl {
	__u32 CT_Rev;		// (& IN_ID)   WORD 0
	__u32 FCS_Type;		// WORD 1
	__u32 Command_code;	// WORD 2
	__u32 reason_code;	// WORD 3
	__u32 FCP;		// WORD 4 (lower byte)

} NSR_PL;



// "FC.H"
#define MAX_RX_SIZE		0x800	// Max Receive Buffer Size is 2048
#define MIN_RX_SIZE		0x100	// Min Size is 256, per FC-PLDA Spec
#define	MAX_TARGET_RXIDS	SEST_DEPTH
#define TARGET_RX_SIZE		SEST_BUFFER_LENGTH

#define CLASS_1			0x01
#define CLASS_2			0x02
#define CLASS_3			0x03

#define FC_PH42			0x08
#define FC_PH43			0x09
#define FC_PH3			0x20

#define RR_TOV			2	// Minimum Time for target to wait for
					// PDISC after a LIP.
#define E_D_TOV			2	// Minimum Time to wait for Sequence
					// Completion.
#define R_A_TOV			0	// Minimum Time for Target to wait
					// before reclaiming resources.
//
//      R_CTL Field
//
//      Routing Bits (31-28)
//
#define FC4_DEVICE_DATA		0x00000000
#define EXT_LINK_DATA		0x20000000
#define FC4_LINK_DATA		0x30000000
#define VIDEO_DATA		0x40000000
#define BASIC_LINK_DATA		0x80000000
#define LINK_CONTROL		0xC0000000
#define ROUTING_MASK		0xF0000000

//
//      Information Bits (27-24)
//
#define UNCAT_INFORMATION	0x00000000
#define SOLICITED_DATA		0x01000000
#define UNSOLICITED_CONTROL	0x02000000
#define SOLICITED_CONTROL	0x03000000
#define UNSOLICITED_DATA	0x04000000
#define DATA_DESCRIPTOR		0x05000000
#define UNSOLICITED_COMMAND	0x06000000
#define COMMAND_STATUS		0x07000000
#define INFO_MASK		0x0F000000
//
//      (Link Control Codes)
//
#define ACK_1			0x00000000
#define ACK_0_OR_N		0x01000000
#define P_RJT			0x02000000
#define F_RJT			0x03000000
#define P_BSY			0x04000000
#define FABRIC_BUSY_TO_DF	0x05000000	// Fabric Busy to Data Frame
#define FABRIC_BUSY_TO_LC	0x06000000	// Fabric Busy to Link Ctl Frame
#define LINK_CREDIT_RESET	0x07000000
//
//      (Link Service Command Codes)
//
//#define LS_RJT                        0x01000000      // LS Reject

#define LS_ACC			0x02000000	// LS Accept
#define LS_PLOGI		0x03000000	// N_PORT Login
#define LS_FLOGI		0x04000000	// F_PORT Login
#define LS_LOGO			0x05000000	// Logout
#define LS_ABTX			0x06000000	// Abort Exchange
#define LS_RCS			0x07000000	// Read Connection Status
#define LS_RES			0x08000000	// Read Exchange Status
#define LS_RSS			0x09000000	// Read Sequence Status
#define LS_RSI			0x0A000000	// Request Seq Initiative
#define LS_ESTS			0x0B000000	// Establish Steaming
#define LS_ESTC			0x0C000000	// Estimate Credit
#define LS_ADVC			0x0D000000	// Advice Credit
#define LS_RTV			0x0E000000	// Read Timeout Value
#define LS_RLS			0x0F000000	// Read Link Status
#define LS_ECHO			0x10000000	// Echo
#define LS_TEST			0x11000000	// Test
#define LS_RRQ			0x12000000	// Reinstate Rec. Qual.
#define LS_PRLI			0x20000000	// Process Login
#define LS_PRLO			0x21000000	// Process Logout
#define LS_TPRLO		0x24000000	// 3rd Party Process Logout
#define LS_PDISC		0x50000000	// Process Discovery
#define LS_FDISC		0x51000000	// Fabric Discovery
#define LS_ADISC		0x52000000	// Discover Address
#define LS_RNC			0x53000000	// Report Node Capability
#define LS_SCR                  0x62000000	// State Change Registration
#define LS_MASK			0xFF000000

//
//      TYPE Bit Masks
//
#define BASIC_LINK_SERVICE	0x00000000
#define EXT_LINK_SERVICE	0x01000000

#define LLC			0x04000000
#define LLC_SNAP		0x05000000
#define SCSI_FCP		0x08000000
#define SCSI_GPP		0x09000000
#define IPI3_MASTER		0x11000000
#define IPI3_SLAVE		0x12000000
#define IPI3_PEER		0x13000000
#define CP_IPI3_MASTER		0x15000000
#define CP_IPI3_SLAVE		0x16000000
#define CP_IPI3_PEER		0x17000000
#define SBCCS_CHANNEL		0x19000000
#define SBCCS_CONTROL		0x1A000000
#define FIBRE_SERVICES		0x20000000
#define FC_FG			0x21000000
#define FC_XS			0x22000000
#define FC_AL			0x23000000
#define SNMP			0x24000000
#define HIPPI_FP		0x40000000
#define TYPE_MASK		0xFF000000

typedef struct {
	__u8 seq_id_valid;
	__u8 seq_id;
	__u16 reserved;	// 2 bytes reserved
	__u32 ox_rx_id;
	__u16 low_seq_cnt;
	__u16 high_seq_cnt;
} BA_ACC_PAYLOAD;

typedef struct {
	__u8 reserved;
	__u8 reason_code;
	__u8 reason_explain;
	__u8 vendor_unique;
} BA_RJT_PAYLOAD;


typedef struct {
	__u32 command_code;
	__u32 sid;
	__u16 ox_id;
	__u16 rx_id;
} RRQ_MESSAGE;

typedef struct {
	__u32 command_code;
	__u8 vendor;
	__u8 explain;
	__u8 reason;
	__u8 reserved;
} REJECT_MESSAGE;


#define	N_OR_F_PORT		0x1000
#define RANDOM_RELATIVE_OFFSET	0x4000
#define CONTINUOSLY_INCREASING	0x8000

#define CLASS_VALID		0x8000
#define INTERMIX_MODE		0x4000
#define TRANSPARENT_STACKED	0x2000
#define LOCKDOWN_STACKED	0x1000
#define SEQ_DELIVERY		0x800

#define XID_NOT_SUPPORTED	0x00
#define XID_SUPPORTED		0x4000
#define XID_REQUIRED		0xC000

#define ASSOCIATOR_NOT_SUPPORTED	0x00
#define ASSOCIATOR_SUPPORTED	0x1000
#define ASSOCIATOR_REQUIRED	0x3000

#define	INIT_ACK0_SUPPORT	0x800
#define INIT_ACKN_SUPPORT	0x400

#define	RECIP_ACK0_SUPPORT	0x8000
#define RECIP_ACKN_SUPPORT	0x4000

#define X_ID_INTERLOCK		0x2000

#define ERROR_POLICY		0x1800	// Error Policy Supported
#define ERROR_DISCARD		0x00	// Only Discard Supported
#define ERROR_DISC_PROCESS	0x02	// Discard and process supported

#define NODE_ID			0x01
#define IEEE_EXT		0x20

//
// Categories Supported Per Sequence
//
#define	CATEGORIES_PER_SEQUENCE	0x300
#define ONE_CATEGORY_SEQUENCE	0x00	// 1 Category per Sequence
#define TWO_CATEGORY_SEQUENCE	0x01	// 2 Categories per Sequence
#define MANY_CATEGORY_SEQUENCE	0x03	// > 2 Categories/Sequence

typedef struct {

	__u16 initiator_control;
	__u16 service_options;

	__u16 rx_data_size;
	__u16 recipient_control;

	__u16 ee_credit;
	__u16 concurrent_sequences;

	__u16 reserved;
	__u16 open_sequences;

} CLASS_PARAMETERS;

typedef struct {
	__u32 login_cmd;
	//
	// Common Service Parameters
	//
	struct {

		__u16 bb_credit;
		__u8 lowest_ver;
		__u8 highest_ver;

		__u16 bb_rx_size;
		__u16 common_features;

		__u16 rel_offset;
		__u16 concurrent_seq;


		__u32 e_d_tov;
	} cmn_services;

	//
	// Port Name
	//
	__u8 port_name[8];

	//
	// Node/Fabric Name
	//
	__u8 node_name[8];

	//
	// Class 1, 2 and 3 Service Parameters
	//
	CLASS_PARAMETERS class1;
	CLASS_PARAMETERS class2;
	CLASS_PARAMETERS class3;

	__u32 reserved[4];

	//
	// Vendor Version Level
	//
	__u8 vendor_id[2];
	__u8 vendor_version[6];
	__u32 buffer_size;
	__u16 rxid_start;
	__u16 total_rxids;
} LOGIN_PAYLOAD;


typedef struct {
	__u32 cmd;		// 4 bytes
	__u8 n_port_identifier[3];
	__u8 reserved;
	__u8 port_name[8];
} LOGOUT_PAYLOAD;


//
//      PRLI Request Service Parameter Defines
//
#define PRLI_ACC			0x01
#define PRLI_REQ			0x02
#define ORIG_PROCESS_ASSOC_VALID	0x8000
#define RESP_PROCESS_ASSOC_VALID	0x4000
#define ESTABLISH_PAIR			0x2000
#define DATA_OVERLAY_ALLOWED		0x40
#define	INITIATOR_FUNCTION		0x20
#define	TARGET_FUNCTION			0x10
#define CMD_DATA_MIXED			0x08
#define DATA_RESP_MIXED			0x04
#define READ_XFER_RDY			0x02
#define WRITE_XFER_RDY			0x01

#define RESPONSE_CODE_MASK	0xF00
#define REQUEST_EXECUTED	0x100
#define NO_RESOURCES		0x200
#define INIT_NOT_COMPLETE	0x300
#define IMAGE_DOES_NOT_EXIST	0x400
#define BAD_PREDEFINED_COND	0x500
#define REQ_EXEC_COND		0x600
#define NO_MULTI_PAGE		0x700

typedef struct {
	__u16 payload_length;
	__u8 page_length;
	__u8 cmd;


	__u32 valid;

	__u32 orig_process_associator;

	__u32 resp_process_associator;

	__u32 fcp_info;
} PRLI_REQUEST;

typedef struct {

	__u16 payload_length;
	__u8 page_length;
	__u8 cmd;

	__u32 valid;
	__u32 orig_process_associator;

	__u32 resp_process_associator;
	__u32 reserved;
} PRLO_REQUEST;

typedef struct {
	__u32 cmd;

	__u32 hard_address;

	__u8 port_name[8];

	__u8 node_name[8];

	__u32 s_id;
} ADISC_PAYLOAD;

struct ext_sg_entry_t {
	__u32 len:18;		/* buffer length, bits 0-17 */
	__u32 uba:13;		/* upper bus address bits 18-31 */
	__u32 lba;		/* lower bus address bits 0-31 */
};

// J. McCarty's LINK.H
//
//      LS_RJT Reason Codes
//

#define INVALID_COMMAND_CODE	0x01
#define LOGICAL_ERROR		0x03
#define LOGICAL_BUSY		0x05
#define PROTOCOL_ERROR		0x07
#define UNABLE_TO_PERFORM	0x09
#define COMMAND_NOT_SUPPORTED	0x0B
#define LS_VENDOR_UNIQUE	0xFF

//
//      LS_RJT Reason Codes Explanations
//
#define NO_REASON		0x00
#define OPTIONS_ERROR		0x01
#define INITIATOR_CTL_ERROR	0x03
#define RECIPIENT_CTL_ERROR	0x05
#define DATA_FIELD_SIZE_ERROR	0x07
#define CONCURRENT_SEQ_ERROR	0x09
#define CREDIT_ERROR		0x0B
#define INVALID_PORT_NAME	0x0D
#define INVALID_NODE_NAME	0x0E
#define INVALID_CSP		0x0F	// Invalid Service Parameters
#define INVALID_ASSOC_HDR	0x11	// Invalid Association Header
#define ASSOC_HDR_REQUIRED	0x13	// Association Header Required
#define LS_INVALID_S_ID		0x15
#define INVALID_OX_RX_ID	0x17	// Invalid OX_ID RX_ID Combination
#define CMD_IN_PROCESS		0x19
#define INVALID_IDENTIFIER	0x1F	// Invalid N_PORT Identifier
#define INVALID_SEQ_ID		0x21
#define ABT_INVALID_XCHNG	0x23	// Attempt to Abort an invalid Exchange
#define ABT_INACTIVE_XCHNG	0x25	// Attempt to Abort an inactive Exchange
#define NEED_REC_QUAL		0x27	// Recovery Qualifier required
#define NO_LOGIN_RESOURCES	0x29	// No resources to support login
#define NO_DATA			0x2A	// Unable to supply requested data
#define	REQUEST_NOT_SUPPORTED	0x2C	// Request Not Supported

//
//      Link Control Codes
//

//
//      P_BSY Action Codes
//
#define SEQUENCE_TERMINATED	0x01000000
#define SEQUENCE_ACTIVE		0x02000000

//
//      P_BSY Reason Codes
//
#define PHYS_NPORT_BUSY		0x010000
#define NPORT_RESOURCE_BUSY	0x020000

//
//      P_RJT, F_RJT Action Codes
//

#define RETRYABLE_ERROR		0x01000000
#define NON_RETRYABLE_ERROR	0x02000000

//
//      P_RJT, F_RJT Reason Codes
//
#define INVALID_D_ID		0x010000
#define INVALID_S_ID		0x020000
#define NPORT_NOT_AVAIL_TMP	0x030000
#define NPORT_NOT_AVAIL_PERM	0x040000
#define CLASS_NOT_SUPPORTED	0x050000
#define USAGE_ERROR		0x060000
#define TYPE_NOT_SUPPORTED	0x070000
#define INVAL_LINK_CONTROL	0x080000
#define INVAL_R_CTL		0x090000
#define INVAL_F_CTL		0x0A0000
#define INVAL_OX_ID		0x0B0000
#define INVAL_RX_ID		0x0C0000
#define INVAL_SEQ_ID		0x0D0000
#define INVAL_DF_CTL		0x0E0000
#define INVAL_SEQ_CNT		0x0F0000
#define INVAL_PARAMS		0x100000
#define EXCHANGE_ERROR		0x110000
#define LS_PROTOCOL_ERROR	0x120000
#define INCORRECT_LENGTH	0x130000
#define UNEXPECTED_ACK		0x140000
#define LOGIN_REQ		0x160000
#define EXCESSIVE_SEQ		0x170000
#define NO_EXCHANGE		0x180000
#define SEC_HDR_NOT_SUPPORTED	0x190000
#define NO_FABRIC		0x1A0000
#define P_VENDOR_UNIQUE		0xFF0000

//
//      BA_RJT Reason Codes
//
#define BA_INVALID_COMMAND	0x00010000
#define BA_LOGICAL_ERROR	0x00030000
#define BA_LOGICAL_BUSY		0x00050000
#define BA_PROTOCOL_ERROR	0x00070000
#define BA_UNABLE_TO_PERFORM	0x00090000

//
//      BA_RJT Reason Explanation Codes
//
#define BA_NO_REASON		0x00000000
#define BA_INVALID_OX_RX	0x00000300
#define BA_SEQUENCE_ABORTED	0x00000500



#endif				/* CPQFCTSSTRUCTS_H      */
